#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include "thread.hpp"
#include "log.hpp"
#include "lockguard.hpp"

using namespace threadModel;
using namespace log_namespace;

static const int gdedefaultnum = 5;

// void test()
// {
//     while (true)
//     {
//         // std::cout << "hello world" << std::endl;
//         sleep(1);
//     }
    
// }

template <typename T>
class threadPool
{
private:
    void lockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void wakeupforonethread()
    {
        pthread_cond_signal(&_cond);
    }

    void wakeupforallthread()
    {
        pthread_cond_broadcast(&_cond);
    }

    void waitbycond()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    bool taskQisEmpty()
    {
        return _taskqueue.empty();
    }

    void handlerTask(const std::string &name)
    {
        while (true)
        {
            lockQueue();
            while (taskQisEmpty() && _isrunning == true)
            {
                _numofsleepthread++;
                LOG(INFO, "%s thread sleep begin!\n", name.c_str());
                waitbycond();
                LOG(INFO, "%s thread wake up!\n", name.c_str());
                _numofsleepthread--;
            }

            if (taskQisEmpty() && !_isrunning)
            {
                // std::cout << name << " quit" << std::endl;
                unlockQueue();
                LOG(INFO, "%s thread quit!\n", name.c_str());
                break;
            }
            
            
            T t = _taskqueue.front();
            _taskqueue.pop();
            unlockQueue();

            // 注意：处理任务不能在临界区中进行
            t();
            // std::cout <<"thread name: " << name << std::endl;
            // std::cout << t.result() << std::endl;
            LOG(DEBUG, "handle task done, task is: %s\n", t.result().c_str());
        }
    }

    //构造函数私有，就是为了单例模式
    threadPool(int threadnum = gdedefaultnum)
        :_threadnum(threadnum)
        ,_isrunning(false)
        ,_numofsleepthread(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    void init()
    {
        func_t func = std::bind(&threadPool::handlerTask, this, std::placeholders::_1);
        for (int i = 0; i < _threadnum; i++)
        {
            std::string threadname = "thread-" + std::to_string(i + 1);
            _threads.emplace_back(threadname, func);
            LOG(DEBUG, "construct thread %s done, init success\n ", threadname.c_str());
        }
    }

    void start()
    {
        _isrunning = true;
        for (auto& thread : _threads)
        {
            LOG(DEBUG, "start thread %s done.\n", thread.name().c_str());
            thread.start();
        }
        
    }

    //强行把程序员和编译器生成的拷贝构造和赋值重载这两种成员函数删除
    threadPool(const threadPool<T> &) = delete;
    void operator=(const threadPool<T> &) = delete;

public:
    // threadPool(int threadnum = gdedefaultnum)
    //     :_threadnum(threadnum)
    //     ,_isrunning(false)
    //     ,_numofsleepthread(0)
    // {
    //     pthread_mutex_init(&_mutex, nullptr);
    //     pthread_cond_init(&_cond, nullptr);
    // }

    // void init()
    // {
    //     func_t func = std::bind(&threadPool::handlerTask, this, std::placeholders::_1);
    //     for (int i = 0; i < _threadnum; i++)
    //     {
    //         std::string threadname = "thread-" + std::to_string(i + 1);
    //         _threads.emplace_back(threadname, func);
    //         LOG(DEBUG, "construct thread %s done, init success\n ", threadname.c_str());
    //     }
    // }

    // void start()
    // {
    //     _isrunning = true;
    //     for (auto& thread : _threads)
    //     {
    //         LOG(DEBUG, "start thread %s done.\n", thread.name().c_str());
    //         thread.start();
    //     }
        
    // }

    void stop()
    {
        lockQueue();
        _isrunning = false;
        wakeupforallthread();
        unlockQueue();
        LOG(INFO, "Thread pool stop success!\n");
    }

    //
    static threadPool<T> *getInstance()
    {
        // 加在最外面的这个判断if (_tp == nullptr)，只是为了实现下述的功能
        // 第一次创建对象时，所有线程中只有竞争锁成功的线程能创建
        // 之后在创建对象时，不会去调用竞争锁的程序，
        // 申请锁不仅会带来资源的消耗，还会让所有线程都参与进来，这导致执行效率也会下降
        if (_tp == nullptr)
        {
            lockGuard lguard(&_mutexforsinglemodel);
            if (_tp == nullptr)
            {
                LOG(INFO, "create threadpool\n");
                _tp = new threadPool();
                _tp->init();
                _tp->start();
            }
            else
            {
                LOG(INFO, "get threadpool\n");
            }
        }
        return _tp;
    }

    void enqueue(const T& in)
    {
        lockQueue();
        if (_isrunning)
        {
            _taskqueue.push(in);
            if(_numofsleepthread > 0)
            {
                wakeupforonethread();
            }
        }

        unlockQueue();

    }

    ~threadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _threadnum;
    std::vector<mythread> _threads;
    std::queue<T> _taskqueue;
    bool _isrunning;

    int _numofsleepthread;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    // volatile 保证了即使程序员使用了做优化的编译器，
    // 也不会创建多个对象
    // volatile static threadPool<T> *_tp;
    static threadPool<T> *_tp;
    static pthread_mutex_t _mutexforsinglemodel;
};

// 静态的指针初始化，只能在类外初始化
template<typename T>
threadPool<T> *threadPool<T>::_tp = nullptr;

template<typename T>
pthread_mutex_t threadPool<T>::_mutexforsinglemodel = PTHREAD_MUTEX_INITIALIZER;
